/*
    This source file is part of GeNa project.
    Copyright © GeNa project 2008
    For the latest info, see http://code.google.com/p/genaproject/ or  http://lumpyproject.forums-rpg.com

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    Foobar is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with Foobar.  If not, see <http://www.gnu.org/licenses/>. */

#ifndef MESH_H_INCLUDED
#define MESH_H_INCLUDED

#include <map>

#include "bufferobject.h"
#include "vertexdecl.h"
#include "dom/domMesh.h"
#include "material.h"

class SubMesh
{
public:
    std::vector<BufferObject*> vertexBuffers;
    std::vector<VertexDeclaration*> decls;
    std::map<std::string, VertexElement*> namedElements;
    std::string materialName;

    BufferObject* indexBuffer;
    GLenum indexType;
    unsigned int count;
    GLenum renderingMode;

    bool linkAttribute( unsigned int attr, std::string name)
    {
        VertexElement* elem = namedElements[name];
        if( elem)
        {
            vertexBuffers[elem->buffer]->bind();
            return elem->linkAttribute(attr);
        }
        return false;
    }

    bool linkAttribute( int attr, unsigned int buffer, unsigned int pos)
    {
        if( buffer >= decls.size())
            return false;
        VertexDeclaration* decl = decls[buffer];
        if( !decl)
            return false;

        if( buffer >= decl->elems.size())
            return false;
        VertexElement* elem = decl->elems[buffer];
        if( elem)
        {
            vertexBuffers[elem->buffer]->bind();
            return elem->linkAttribute(attr);
        }
        return false;
    }

    void draw(GLenum _renderingMode = 0)
    {
        if( !_renderingMode)
            _renderingMode = renderingMode;

        indexBuffer->bind();

        glDrawElements( _renderingMode, count, indexType, NULL);
    }

    template<class T> void loadPrimitive( T & primitive, GLenum _renderingMode);
    template<class T, typename U > void fillBufferElem(domAccessor* accessor, unsigned int index,  T & array);
    template<class T> void fillBuffer(T input, unsigned int &index);
    template<class T> void inputDecl(T input, unsigned int &index);
};

class Mesh
{
public:
    std::list<SubMesh*> m_subMeshes;

    Mesh(domMesh* mesh);
};

#endif // MESH_H_INCLUDED
